'''
Created on Oct 11, 2012

@author: raygomez
'''
from MessageHeader import MessageHeader
from AVP import AVP

class Message:
    def __init__(self, that=None):
        if not that:
            self.hdr = MessageHeader()
            self.avp = []
        else:
            self.hdr = MessageHeader(that.hdr)
            self.avp = that.avp[:]
            
    def encodeSize(self):
        size = self.hdr.encodeSize()
        for a in self.avp:
            size += a.encodeSize()
        return size
    
    def encode(self, packer):
        size = self.encodeSize()
        self.hdr.encode(packer, size)
        for a in self.avp:
            a.encode(packer)
    
    DECODE_STATUS_DECODED = 0
    DECODE_STATUS_NOT_ENOUGH = 1
    DECODE_STATUS_GARBAGE = 2
    
    @staticmethod
    def decodeSize(unpacker):
        start = unpacker.get_position()
        versionLength = unpacker.unpack_uint()
        version = versionLength >> 24
        size = versionLength & 0xFFFFFF
        
        if size < 20: size = 4
        if (size % 4) != 0: sizes = 20
        return size
    
    def decode(self, unpacker, remainingBytes):
        
        start = unpacker.get_position()
        if remainingBytes < 4:
            return Message.DECODE_STATUS_NOT_ENOUGH
        versionLength = unpacker.unpack_uint()
        version = versionLength >> 24
        size = versionLength & 0xFFFFFF
        
        if version != 1:
            return Message.DECODE_STATUS_GARBAGE
        if size < 20:
            return Message.DECODE_STATUS_GARBAGE
        if size % 4 != 0:
            return Message.DECODE_STATUS_GARBAGE
        
        unpacker.set_position(start)
        
        if remainingBytes < size:
            return Message.DECODE_STATUS_NOT_ENOUGH
        
        self.hdr.decode(unpacker)
        self.avp = []
        bytesLeft = remainingBytes - 20
        while bytesLeft > 0:
            if bytesLeft < 8:
                return Message.DECODE_STATUS_GARBAGE
            avpSize = AVP.decodeSize(unpacker, bytesLeft)
            if avpSize == 0: return Message.DECODE_STATUS_GARBAGE
            if avpSize > bytesLeft: return Message.DECODE_STATUS_GARBAGE
            
            a = AVP(0, [])
            a.decode(unpacker, avpSize)
            self.avp.append(a)
            bytesLeft -= avpSize
            
        return Message.DECODE_STATUS_DECODED
    
    def prepareResponse(self, request):
        self.hdr.prepareResponse(request.hdr)
    
    def __len__(self):
        return len(self.avp)
    
    def __getitem__(self,key):
        return self.avp[key]
    
    def __setitem__(self, key, value):
        self.avp[key] = value
    
    def __delitem__(self, key):
        del self.avp[key]
        
    def __iter__(self):
        return self.avp.__iter__()
    
    def __str__(self):
        messageStr = str(self.hdr)
        for a in self.avp:
            messageStr += str(a) 
        return messageStr
        
    def append(self, a):
        self.avp.append(a)
        
    def subset(self, code, vendorId=0):
        
        class AVPSubset:
            def __init__(self, message, code, vendorId):
                self.message = message
                self.code = code
                self.vendorId = vendorId
                self.iter = message.__iter__()
                
            def __iter__(self):
                return self
            
            def next(self):
                while True:
                    a = self.iter.next()
                    if a.code == self.code and a.vendorId == self.vendorId:
                        return a
        return AVPSubset(self, code, vendorId)
    
    def find(self, code, vendorId = 0):
        for a in self.avp:
            if a.code == code and a.vendorId == vendorId:
                return a
                
    def count(self, code, vendorId = 0):
        c = 0
        for a in self.avp:
            if a.code == code and a.vendorId == vendorId:
                c +=1
        return c
    